/**
 * @file utils
 * @author  fanxl
 */
import {toPath, cloneDeep, isObject, isPlainObject, isArray, isEmpty, includes, uniqueId, every, keys} from 'lodash-es';
import type {NestedObjectTypeValue, SimpleDataTypeValue, ShallowObjectType} from './types';
import type {UnionSpecItem, RulesItem} from '../interface';
import dayjs from 'dayjs';

// 索引匹配中括号的正则
export const keyReg = /^\[(.*)\]$/;

export const formatKey = (key: string) => {
    const matchResult = keyReg.exec(key);
    if (matchResult) {
        return matchResult[1];
    }
    return key;
};

// 是否为嵌套层级的字符串
export const isNestedString = (key: string): boolean => {
    return key.includes('.');
};

export const getValueByKeyPath = (values: any, keyPath: string, defaulValue: any) => {
    let obj = cloneDeep(values);
    const path = toPath(keyPath);
    let currentIndex = 0;
    while (obj && currentIndex < path.length) {
        obj = obj[path[currentIndex++]];
    }
    return obj === undefined ? defaulValue : obj;
};

// 生成随机字符串
export const createRandomChars = (len: number = 8): string => {
    const randomChar = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890';
    const charLen = randomChar.length;
    let n = '';
    for (let i = 0; i < len; i++) {
        n += randomChar.charAt(Math.floor(Math.random() * charLen));
    }
    return n;
};

export const getTouched = (obj: NestedObjectTypeValue<boolean>): boolean => {
    if (isPlainObject(obj)) {
        const values = Object.values(obj);
        if (isEmpty(values)) {
            return true;
        }
        return values.every((value) => {
            if (!isObject(value)) {
                return value === true;
            }
            if (isPlainObject(value)) {
                return getTouched(value as NestedObjectTypeValue<boolean>);
            }
            if (isArray(value)) {
                return value.every((el) => getTouched(el));
            }
        });
    }
    if (isArray(obj)) {
        return obj.every((el) => getTouched(el));
    }
    return Boolean(obj);
};

export const convertLeafValue = (obj: any, value?: boolean): any => {
    if (typeof obj !== 'object') {
        return value === undefined ? false : value;
    }
    if (Array.isArray(obj)) {
        return obj.map((v) => convertLeafValue(v, value));
    }
    return Object.keys(obj).reduce((acc, key) => {
        return {...acc, [key]: convertLeafValue(obj[key], value)};
    }, {});
};

export const isSimpleDataType = (spec: UnionSpecItem): boolean => {
    const {dataType} = spec;
    return includes(['BOOL', 'COLOR', 'ENUM', 'HTML', 'NUMBER', 'STRING', 'UPLOAD', 'URL', 'VIDEO', 'AUDIO'], dataType);
};

let uniqueNumber = 1;

const getUniqueNumber = (): number => ++uniqueNumber;
const getUniqueColor = (): string => {
    const start = parseInt('f00000', 16);
    return `#${Number(start + getUniqueNumber()).toString(16)}`;
};

// 示例静态资源
const imageExampleUrl = 'https://dummyimage.com/500x500.jpg';
const videoExampleUrl = '';
const audioExampleUrl = '';

const genUniqueStringByRules = (rules: RulesItem): string => {
    const {email, phone, telephone, fax, mobilephone, businessPhone, date = {}, link, imageUrl, videoUrl} = rules;
    // 返回url格式
    if (link) {
        return uniqueId('https://www.meshed.data/url_');
    }
    if (imageUrl) {
        return `${imageExampleUrl}?${uniqueId('img_')}=1`;
    }
    if (videoUrl) {
        return `${videoExampleUrl}?${uniqueId('video_')}=1`;
    }
    // 返回邮箱格式
    if (email) {
        return `bd${uniqueId()}@qq.com`;
    }
    // 返回固定电话格式
    if (phone || telephone || fax) {
        return `021-${20680000 + getUniqueNumber()}`;
    }
    // 返回移动电话格式
    if (mobilephone) {
        return `${13500000000 + getUniqueNumber()}`;
    }
    // 返回商业电话格式
    if (businessPhone) {
        return `${40080000000 + getUniqueNumber()}`;
    }
    // 返回日期格式
    if (!isEmpty(date)) {
        const {format = 'YYYY-MM-DD'} = date;
        const uniqueDate = dayjs().add(getUniqueNumber());
        return uniqueDate.format(format);
    }
    return uniqueId('string-');
};

export const genUniqMeshedValue = (spec: UnionSpecItem, fieldValue: SimpleDataTypeValue): SimpleDataTypeValue => {
    const {dataType, rules = {}, display} = spec;
    const {required} = rules;
    let uniqValue: SimpleDataTypeValue;
    switch (dataType) {
        case 'STRING':
            uniqValue = fieldValue || required ? genUniqueStringByRules(rules) : '';
            break;
        case 'UPLOAD':
            uniqValue = fieldValue || required ? `${imageExampleUrl}?${uniqueId('img_')}=1` : '';
            break;
        case 'URL':
            uniqValue = fieldValue || required ? uniqueId('https://www.meshed.data/url_') : '';
            break;
        case 'VIDEO':
            uniqValue = fieldValue || required ? `${videoExampleUrl}?${uniqueId('video_')}=1` : '';
            break;
        case 'AUDIO':
            uniqValue = fieldValue || required ? `${audioExampleUrl}?${uniqueId('audio_')}=1` : '';
            break;
        case 'NUMBER':
            uniqValue = display !== 'none' ? getUniqueNumber() : fieldValue;
            break;
        case 'HTML':
            uniqValue = fieldValue || required ? uniqueId('html-') : '';
            break;
        case 'COLOR':
            uniqValue = fieldValue || required ? getUniqueColor() : '';
            break;
        default:
            uniqValue = fieldValue;
            break;
    }
    return uniqValue;
};

export const isEmptyAlternativeValue = (
    value: ShallowObjectType<SimpleDataTypeValue | ShallowObjectType<SimpleDataTypeValue>>,
    spec: UnionSpecItem
): boolean => {
    const dataType = spec.dataType;
    if ('ALTERNATIVE' === dataType && keys(value).length === 1) {
        return every(value, (item) => isEmpty(item));
    }
    return false;
};
